#include "stdafx.h"

#include "hwinclass.h"
#include "hwinapplication.h"


namespace harlinn
{
    namespace windows
    {
        String HWIN_EXPORT WindowClass::animate_class_name = String(ANIMATE_CLASS);
        String HWIN_EXPORT WindowClass::datetimepick_class_name = String(DATETIMEPICK_CLASS);
        String HWIN_EXPORT WindowClass::hotkey_class_name = String(HOTKEY_CLASS);
        String HWIN_EXPORT WindowClass::link_class_name = String(WC_LINK);
        String HWIN_EXPORT WindowClass::monthcal_class_name = String(MONTHCAL_CLASS);
        String HWIN_EXPORT WindowClass::nativefontctl_class_name = String(WC_NATIVEFONTCTL);
        String HWIN_EXPORT WindowClass::progress_class_name = String(PROGRESS_CLASS);
        String HWIN_EXPORT WindowClass::rebar_class_name = String(REBARCLASSNAME);
        String HWIN_EXPORT WindowClass::status_class_name = String(STATUSCLASSNAME);
        String HWIN_EXPORT WindowClass::toolbar_class_name = String(TOOLBARCLASSNAME);
        String HWIN_EXPORT WindowClass::tooltips_class_name = String(TOOLTIPS_CLASS);
        String HWIN_EXPORT WindowClass::trackbar_class_name = String(TRACKBAR_CLASS);
        String HWIN_EXPORT WindowClass::updown_class_name = String(UPDOWN_CLASS);
        String HWIN_EXPORT WindowClass::button_class_name = String(WC_BUTTON);
        String HWIN_EXPORT WindowClass::combobox_class_name = String(WC_COMBOBOXEX);
        String HWIN_EXPORT WindowClass::edit_class_name = String(WC_EDIT);
        String HWIN_EXPORT WindowClass::header_class_name = String(WC_HEADER);
        String HWIN_EXPORT WindowClass::listbox_class_name = String(WC_LISTBOX);
        String HWIN_EXPORT WindowClass::ipaddress_class_name = String(WC_IPADDRESS);
        String HWIN_EXPORT WindowClass::listview_class_name = String(WC_LISTVIEW);
        String HWIN_EXPORT WindowClass::pagescroller_class_name = String(WC_PAGESCROLLER);
        String HWIN_EXPORT WindowClass::scrollbar_class_name = String(WC_SCROLLBAR);
        String HWIN_EXPORT WindowClass::static_class_name = String(WC_STATIC);
        String HWIN_EXPORT WindowClass::tabcontrol_class_name = String(WC_TABCONTROL);
        String HWIN_EXPORT WindowClass::treeview_class_name = String(WC_TREEVIEW);



        HWIN_EXPORT WindowClass::WindowClass()
            : style(0), procedure(0), classExtraBytes(0), windowExtraBytes(0), moduleHandle(0),
                icon(0), cursor(0), backgroundBrush(0), smallIcon(0)
        {}

        HWIN_EXPORT WindowClass::WindowClass(const WNDCLASSEX& wndClass)
            : style(wndClass.style), procedure(wndClass.lpfnWndProc), classExtraBytes(wndClass.cbClsExtra), 
            windowExtraBytes(wndClass.cbWndExtra), moduleHandle(wndClass.hInstance),
            icon(wndClass.hIcon), cursor(wndClass.hCursor), backgroundBrush(wndClass.hbrBackground), smallIcon(wndClass.hIconSm)
        {
            if(wndClass.lpszClassName)
            {
                name = String(wndClass.lpszClassName);
            }
            if(wndClass.lpszMenuName)
            {
                menuName = String(wndClass.lpszMenuName);
            }
        }


        HWIN_EXPORT WindowClass::WindowClass(std::shared_ptr<const WindowClass> existingClass)
            : name(existingClass->name),menuName(existingClass->menuName),style(existingClass->style), procedure(existingClass->procedure), classExtraBytes(existingClass->classExtraBytes), 
            windowExtraBytes(existingClass->windowExtraBytes), moduleHandle(existingClass->moduleHandle),
            icon(existingClass->icon), cursor(existingClass->cursor), backgroundBrush(existingClass->backgroundBrush), smallIcon(existingClass->smallIcon)
        {
        }


        HWIN_EXPORT WindowClass::~WindowClass()
        {

        }


        HWIN_EXPORT WindowClass& WindowClass::Register()
        {
            auto application = Application::Current();
            if(application)
            {
                auto windowClasses = application->GetWindowClasses();
                if(windowClasses)
                {
                    auto self = As<WindowClass>();
                    windowClasses->Register(self);
                    
                }
            }
            return *this;
        }



        HWIN_EXPORT WNDCLASSEX WindowClass::AsWNDCLASSEX() const
        {
            WNDCLASSEX result = {0,};

            result.cbSize = sizeof(WNDCLASSEX);
            result.style = this->GetStyle();
            result.lpfnWndProc = this->GetProcedure();
            result.cbClsExtra = this->GetClassExtraBytes();
            result.cbWndExtra = this->GetWindowExtraBytes();
            result.hInstance = this->GetModuleHandle();
            result.hIcon = this->GetIcon();
            result.hCursor = this->GetCursor();
            result.hbrBackground = this->GetBackgroundBrush();
            if(menuName.length())
            {
                result.lpszMenuName = menuName.c_str();
            }
            else
            {
                result.lpszMenuName = nullptr;
            }
            if(name.length())
            {
                result.lpszClassName = name.c_str();
            }
            else
            {
                result.lpszClassName = nullptr;
            }
            result.hIconSm = this->GetSmallIcon();

            return result;
        }


        HWIN_EXPORT const String& WindowClass::GetName() const
        {
            return name;
        }

        HWIN_EXPORT WindowClass& WindowClass::SetName( const String& theName)
        {
            name = theName;
            return *this;
        }


        HWIN_EXPORT const String& WindowClass::GetMenuName() const
        {
            return menuName;
        }

        HWIN_EXPORT WindowClass& WindowClass::SetMenuName(const String& theMenuName)
        {
            menuName = theMenuName;
            return *this;
        }


        HWIN_EXPORT UINT WindowClass::GetStyle() const
        {
            return style;
        }

        HWIN_EXPORT WindowClass& WindowClass::SetStyle(UINT theStyle)
        {
            style = theStyle;
            return *this;
        }


        HWIN_EXPORT WNDPROC WindowClass::GetProcedure() const
        {
            return procedure;
        }

        HWIN_EXPORT WindowClass& WindowClass::SetProcedure(WNDPROC theProcedure)
        {
            procedure = theProcedure;
            return *this;
        }


        HWIN_EXPORT int WindowClass::GetClassExtraBytes() const
        {
            return classExtraBytes;
        }

        HWIN_EXPORT WindowClass& WindowClass::SetClassExtraBytes(int theClassExtraBytes)
        {
            classExtraBytes = theClassExtraBytes;
            return *this;
        }


        HWIN_EXPORT int WindowClass::GetWindowExtraBytes() const
        {
            return windowExtraBytes;
        }

        HWIN_EXPORT WindowClass& WindowClass::SetWindowExtraBytes(int theWindowExtraBytes)
        {
            windowExtraBytes = theWindowExtraBytes;
            return *this;
        }


        HWIN_EXPORT HINSTANCE WindowClass::GetModuleHandle() const
        {
            return moduleHandle;
        }

        HWIN_EXPORT WindowClass& WindowClass::SetModuleHandle(HINSTANCE theModuleHandle)
        {
            moduleHandle = theModuleHandle;
            return *this;
        }


        HWIN_EXPORT HICON WindowClass::GetIcon() const
        {
            return icon;
        }

        HWIN_EXPORT WindowClass& WindowClass::SetIcon(HICON theIcon)
        {
            icon = theIcon;
            return *this;
        }


        HWIN_EXPORT HCURSOR WindowClass::GetCursor() const
        {
            return cursor;
        }

        HWIN_EXPORT WindowClass& WindowClass::SetCursor(HCURSOR theCursor)
        {
            cursor = theCursor;
            return *this;
        }


        HWIN_EXPORT HBRUSH WindowClass::GetBackgroundBrush() const
        {
            return backgroundBrush;
        }

        HWIN_EXPORT WindowClass& WindowClass::SetBackgroundBrush(HBRUSH theBackgroundBrush)
        {
            backgroundBrush = theBackgroundBrush;
            return *this;
        }


        HWIN_EXPORT HICON WindowClass::GetSmallIcon() const
        {
            return smallIcon;
        }

        HWIN_EXPORT WindowClass& WindowClass::SetSmallIcon(HICON theSmallIcon)
        {
            smallIcon = theSmallIcon;
            return *this;
        }




        HWIN_EXPORT WindowClasses::WindowClasses()
        {
            LoadStandardClasses();
        }

        HWIN_EXPORT WindowClasses::~WindowClasses()
        {
            
        }



        void WindowClasses::LoadStandardClasses()
        {
            LoadStandardClass(WindowClass::animate_class_name);
            LoadStandardClass(WindowClass::datetimepick_class_name);
            LoadStandardClass(WindowClass::hotkey_class_name);
            LoadStandardClass(WindowClass::link_class_name);
            LoadStandardClass(WindowClass::monthcal_class_name);
            LoadStandardClass(WindowClass::nativefontctl_class_name);
            LoadStandardClass(WindowClass::progress_class_name);
            LoadStandardClass(WindowClass::rebar_class_name);
            LoadStandardClass(WindowClass::status_class_name);
            LoadStandardClass(WindowClass::toolbar_class_name);
            LoadStandardClass(WindowClass::tooltips_class_name);
            LoadStandardClass(WindowClass::trackbar_class_name);
            LoadStandardClass(WindowClass::updown_class_name);
            LoadStandardClass(WindowClass::button_class_name);
            LoadStandardClass(WindowClass::combobox_class_name);
            LoadStandardClass(WindowClass::edit_class_name);
            LoadStandardClass(WindowClass::header_class_name);
            LoadStandardClass(WindowClass::listbox_class_name);
            LoadStandardClass(WindowClass::ipaddress_class_name);
            LoadStandardClass(WindowClass::listview_class_name);
            LoadStandardClass(WindowClass::pagescroller_class_name);
            LoadStandardClass(WindowClass::scrollbar_class_name);
            LoadStandardClass(WindowClass::static_class_name);
            LoadStandardClass(WindowClass::tabcontrol_class_name);
            LoadStandardClass(WindowClass::treeview_class_name);

        }


        void WindowClasses::LoadStandardClass(const String& className)
        {
            auto cit = map.find(className);
            if(cit == map.end())
            {
                auto windowClass = GetClassInfo(className);
                map.insert(map_t::value_type(className,windowClass));
            }
        }


        HWIN_EXPORT std::shared_ptr<WindowClass> WindowClasses::GetClassInfo(const String& className)
        {
            auto result = GetClassInfo((HINSTANCE)0,className);
            return result;
        }

        HWIN_EXPORT std::shared_ptr<WindowClass> WindowClasses::GetClassInfo(HINSTANCE hInstance, const String& className)
        {
            WNDCLASSEX wndCls = {0,};
            GetClassInfoEx(hInstance,className.c_str(), &wndCls);
            auto result = std::make_shared<WindowClass>(wndCls);
            return result;
        }

        HWIN_EXPORT std::shared_ptr<WindowClass> WindowClasses::GetWindowClass(const String& className) const
        {
            auto cit = map.find(className);
            if(cit != map.end())
            {
                auto result = (*cit).second;
                return result;
            }
            return std::shared_ptr<WindowClass>();
        }

        HWIN_EXPORT bool WindowClasses::Register(std::shared_ptr<WindowClass> theWindowClass)
        {
            CheckPointerNotNull(theWindowClass);

            auto theName = theWindowClass->GetName();
            if(theName.length())
            {
                auto windowClass = GetWindowClass(theName);
                if(!windowClass)
                {
                    WNDCLASSEX wndCls = theWindowClass->AsWNDCLASSEX();
                    ATOM atom = ::RegisterClassExW(&wndCls);
                    if(!atom)
                    {
                        ThrowLastOSError();
                    }
                    map.insert(map_t::value_type(theName,theWindowClass));
                    return true;
                }
            }
            return false;
        }



    }
}